﻿using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace FastDev
{
    public static class GoapPlanner
    {
        public static void Plan(IGoapAgent goapAgent, GoapAction goal, List<GoapAction> goapActions)
        {
            Queue<GoapAction> queueGoapActions = new Queue<GoapAction>();

            GoapNode curNode = new GoapNode(null);
            curNode.GoapActions.Add(goal);

            while (true)
            {
                for (int i = 0; i < curNode.GoapActions.Count; i++)
                {
                    GoapAction goalAction = curNode.GoapActions[i];
                    foreach (var conditionValue in goalAction.PreCondition.Values)
                    {
                        //当前状态是否符合目标状态
                        if (goapAgent.GoapState.Contains(conditionValue))
                            continue;
                        var selectedActions = GetMatchActions(goapActions, conditionValue);

                        var minCostAction = GetMinCost(goapAgent.GoapState,selectedActions);
                        if (minCostAction == null)
                        {
                            goapAgent.OnPlanFailed(goalAction.Name);
                            return;
                        }
                        if (curNode.Child == null)
                            curNode.Child = new GoapNode(curNode);
                        if (!curNode.Child.GoapActions.Contains(minCostAction))
                        {
                            curNode.Child.GoapActions.Add(minCostAction);
                        }
                    }
                }
                if (curNode.Child == null)
                    break;
                curNode = curNode.Child;
            }

            string actionPath = "";

            while (curNode != null)
            {
                foreach (var item in curNode.GoapActions)
                {
                    actionPath += $"{item.Name}(index:{curNode.Index}) + ->";
                    queueGoapActions.Enqueue(item);
                }
                curNode = curNode.Parent;
            }
            Debug.Log("Goap Action Plan：" + actionPath);

            goapAgent.OnStartPlanSuccess(queueGoapActions);
        }

        private static List<GoapAction> GetMatchActions(List<GoapAction> actions, KeyValuePair<string, int> preCondition)
        {
            List<GoapAction> matchActions = new List<GoapAction>();
            foreach (var a in actions)
            {
                if (a.Effect.Contains(preCondition))
                {
                    matchActions.Add(a);
                }
            }
            return matchActions;
        }

        private static GoapAction GetMinCost(GoapState agentGoapSate, List<GoapAction> actions)
        {
            GoapAction min = null;

            List<GoapAction> containActions = actions.Where((a) => agentGoapSate.Contains(a.PreCondition)).ToList();

            if (containActions.Count > 0)
            {
                actions = containActions;
            }

            foreach (var e in actions)
            {
                if (min == null || e.Cost < min.Cost)
                {
                    min = e;
                }
            }
            return min;
        }
    }
}
